Skip to content

Clarify machine implementation ownership and runtime strategies - #209

Merged
SandroMaglione merged 2 commits into
mainfrom
codex/internal-module-ownership
Sep 6, 2026
Merged

Clarify machine implementation ownership and runtime strategies#209
SandroMaglione merged 2 commits into
mainfrom
codex/internal-module-ownership

Conversation

@SandroMaglione

@SandroMaglione SandroMaglione commented Sep 6, 2026

Copy link
Copy Markdown
Member

Summary

  • Give captured handlers an internal representation accessed through toImpl. Stored transitions were previously described by public selector-factory types or any; planners now consume their actual executable form. Preserve all public exports, fields, and generic signatures.
  • Separate runtime coordination, shared process contracts and ownership, the generic worker, and compiled execution. Shared child ownership receives startup functions from the coordinator, preserving synchronous compiled child startup without cyclic imports. Keep those functions on a shared prototype while each root owns its session counter and inspection state. Reuse public reference contracts in the runtime.
internal/machine/
  runtime.ts          # startup and strategy selection
  runtimeProtocol.ts  # shared contracts, child ownership, observation
  runtimeGeneric.ts   # general Effect worker and supervisor
  runtimeCompiled.ts  # compiled statechart execution
  • Share snapshot structural checks across synchronous and effectful decoding, and define Cluster checkpoint services and wire schemas once. Add malformed-snapshot regressions and Cluster public-contract typetests.
  • Correct the outdated guard documentation, add a compile-checked guarded-construction example, and extend architecture checks to enforce the extracted runtime modules' dependency direction.

Changeset

  • Added or updated for a library or package-metadata change
  • Not required because this PR does not change a publishable package

Patch changeset; no migration required.

Validation

  • pnpm check
  • Automated type-performance measurement passed or was not required
  • Automated runtime- and memory-performance measurement passed or was not required

Local validation passed 714 runtime tests and 1,123 type assertions, including generic-versus-optimized comparisons and independent-root lifecycle checks. Local pnpm perf:types and pnpm perf:runtime passed.

Final-commit CI, type performance, and runtime performance passed. Both comparison artifacts were inspected. Type instantiation counts are identical in every scenario. Five independent processes per version measured throughput changes of -2.2% to +2.4%, idle-machine heap at -0.3%, and all heap-profile changes between -0.7% and +1.2%. The regression guard passed; small timing differences remain informational.

@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Type performance

Measured with TypeScript 6.0.3 and skipLibCheck=true.

Scenario Base PR Difference
Effect only 55 55 0 (0.0%)
Import effect-machine 55 55 0 (0.0%)
Machine.state (3 children) 3,555 3,555 0 (0.0%)
Machine.make (3 states, 2 events) 9,531 9,531 0 (0.0%)
machine.handle (3 states, 2 transitions) 46,813 46,813 0 (0.0%)
fluent transition (10 named branches) 75,251 75,251 0 (0.0%)
atomic construction, guards, and reentry 112,926 112,926 0 (0.0%)
fluent invocation (state-dependent Effect) 67,427 67,427 0 (0.0%)
machine.handle (depth 24) 213,760 213,760 0 (0.0%)
machine.handle (wide depth 16) 267,909 267,909 0 (0.0%)
machine.handle (parallel/history/choice) 126,654 126,654 0 (0.0%)
machine definition (3 independent implementations) 93,482 93,482 0 (0.0%)
machine exact input/output/error/services 77,142 77,142 0 (0.0%)
execution adapter readiness 90,926 90,926 0 (0.0%)

Marginal instantiations are measured against the matching setup without that API call:

Scenario Base PR Difference
Import effect-machine 0 0 0
Machine.state (3 children) 3,500 3,500 0 (0.0%)
Machine.make (3 states, 2 events) 5,968 5,968 0 (0.0%)
machine.handle (3 states, 2 transitions) 37,282 37,282 0 (0.0%)
fluent transition (10 named branches) 58,223 58,223 0 (0.0%)
atomic construction, guards, and reentry 87,782 87,782 0 (0.0%)
fluent invocation (state-dependent Effect) 54,195 54,195 0 (0.0%)
machine.handle (depth 24) 140,736 140,736 0 (0.0%)
machine.handle (wide depth 16) 190,768 190,768 0 (0.0%)
machine.handle (parallel/history/choice) 100,987 100,987 0 (0.0%)
machine definition (3 independent implementations) 71,641 71,641 0 (0.0%)
machine exact input/output/error/services 56,807 56,807 0 (0.0%)
execution adapter readiness 33,907 33,907 0 (0.0%)
Check times (informational)
Scenario Base PR
Effect only 0.03s 0.03s
Import effect-machine 0.03s 0.03s
Machine.state (3 children) 0.11s 0.11s
Machine.make (3 states, 2 events) 0.16s 0.16s
machine.handle (3 states, 2 transitions) 0.39s 0.37s
fluent transition (10 named branches) 0.47s 0.47s
atomic construction, guards, and reentry 0.64s 0.64s
fluent invocation (state-dependent Effect) 0.41s 0.41s
machine.handle (depth 24) 0.65s 0.65s
machine.handle (wide depth 16) 0.78s 0.78s
machine.handle (parallel/history/choice) 0.64s 0.63s
machine definition (3 independent implementations) 0.55s 0.57s
machine exact input/output/error/services 0.50s 0.50s
execution adapter readiness 0.52s 0.52s

Type instantiations are the comparison metric. Check time varies with runner load and is informational only.

@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Runtime performance

Median of 5 independent benchmark processes on AMD EPYC 7763 64-Core Processor with Node v24.20.0.

Pull request baseline

Scenario Effect Machine
Plan counter transitions 108,437 transitions/s
Drain burst with terminal fence 368,106 increments/s
Drain burst with a change observer 342,755 increments/s
Lookup and send to one child 301,091 increments/s
Start and stop a machine 126,183 machines/s
Start and stop a parent with one child 25,587 families/s
Plan transitions through a compound state 94,922 transitions/s
Plan transitions through parallel regions 75,819 transitions/s
Drain burst through a compound state 291,707 events/s
Drain burst through two parallel regions 275,139 events/s
Drain a compound-state burst with a change observer 276,324 events/s

Process runtime reference points

Scenario Effect Machine
Start and stop a raw generic process 14,765 processes/s
Start and stop a raw compiled process 59,485 processes/s
Memory profile Effect Machine
Idle machine 1.9 KiB
Raw generic managed process 13.9 KiB
Raw compiled process 3.2 KiB
Two independent idle machines 3.6 KiB
Idle parent with one child 5.9 KiB
Parent with observed child registry 10.0 KiB
Parent with observed invoked child snapshots 6.5 KiB

Effect Machine change from base

Metric Base Base variability PR PR variability Difference
Plan counter transitions 108,260 transitions/s 1.1% MAD 108,437 transitions/s 0.4% MAD +0.2%
Drain burst with terminal fence 363,024 increments/s 1.4% MAD 368,106 increments/s 1.3% MAD +1.4%
Drain burst with a change observer 341,422 increments/s 1.5% MAD 342,755 increments/s 1.0% MAD +0.4%
Lookup and send to one child 294,147 increments/s 2.4% MAD 301,091 increments/s 0.3% MAD +2.4%
Start and stop a machine 124,146 machines/s 0.9% MAD 126,183 machines/s 0.6% MAD +1.6%
Start and stop a parent with one child 25,333 families/s 2.0% MAD 25,587 families/s 0.5% MAD +1.0%
Plan transitions through a compound state 95,668 transitions/s 0.8% MAD 94,922 transitions/s 0.5% MAD -0.8%
Plan transitions through parallel regions 77,549 transitions/s 1.1% MAD 75,819 transitions/s 1.5% MAD -2.2%
Drain burst through a compound state 287,950 events/s 0.7% MAD 291,707 events/s 1.9% MAD +1.3%
Drain burst through two parallel regions 273,826 events/s 2.3% MAD 275,139 events/s 0.7% MAD +0.5%
Drain a compound-state burst with a change observer 271,590 events/s 0.5% MAD 276,324 events/s 2.0% MAD +1.7%
Idle machine heap per unit 1.9 KiB 1.0% MAD 1.9 KiB 0.1% MAD -0.3%
Raw generic managed process heap per unit 13.9 KiB 0.0% MAD 13.9 KiB 0.0% MAD +0.0%
Raw compiled process heap per unit 3.2 KiB 0.9% MAD 3.2 KiB 0.2% MAD -0.7%
Two independent idle machines heap per unit 3.5 KiB 0.0% MAD 3.6 KiB 0.0% MAD +1.2%
Idle parent with one child heap per unit 5.9 KiB 0.0% MAD 5.9 KiB 0.0% MAD +0.3%
Parent with observed child registry heap per unit 10.0 KiB 0.0% MAD 10.0 KiB 0.0% MAD +0.1%
Parent with observed invoked child snapshots heap per unit 6.4 KiB 0.0% MAD 6.5 KiB 0.1% MAD +0.2%

Process runtime reference change from base

Metric Base Base variability PR PR variability Difference
Start and stop a raw generic process 14,573 processes/s 3.3% MAD 14,765 processes/s 2.5% MAD +1.3%
Start and stop a raw compiled process 60,383 processes/s 1.5% MAD 59,485 processes/s 0.4% MAD -1.5%

Regression guard

No large, noise-adjusted throughput or heap regressions detected.

Versions and interpretation
  • Effect Machine: 0.33.0

Higher throughput is better; lower heap is better. Variability is the median absolute deviation across independent processes, relative to their median. Small differences on shared GitHub-hosted hardware remain informational; the required guard rejects only large changes beyond the measured noise allowance.

@SandroMaglione
SandroMaglione merged commit a10e9be into main Sep 6, 2026
8 checks passed
@SandroMaglione
SandroMaglione deleted the codex/internal-module-ownership branch September 6, 2026 18:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant